﻿using Infrastructure.WebApi;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Infrastructure.Utils
{
    #region 自定义数据验证基础方法
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public abstract class SetValidAttribute : Attribute
    {
        public string _errorMessage { get; set; }
        /// <summary>
        /// 自定义数据验证
        /// </summary>
        /// <param name="oValue"></param>
        /// <returns></returns>
        public abstract ValidResult Validate(object oValue, string propertyName, string displayName);
    }

    /// <summary>
    /// 特性扩展
    /// </summary>
    public static class AttributeExtend
    {
        /// <summary>
        /// 自定义属性验证
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static List<List<ValidResult>> SetValid<T>(this T t, List<List<ValidResult>> listError = null)
        {
            listError = listError ?? new List<List<ValidResult>>();
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string) && !prop.PropertyType.IsGenericType && !prop.PropertyType.IsArray)
                {
                    var oValue = prop.GetValue(t, null);
                    if (oValue != null) SetValid(prop.GetValue(t, null), listError);
                }
                else
                {
                    if (prop.IsDefined(typeof(SetValidAttribute), true))
                    {
                        var listErrorProp = new List<ValidResult>();
                        var oValue = prop.GetValue(t, null);
                        foreach (SetValidAttribute item in prop.GetCustomAttributes(typeof(SetValidAttribute), true))//获取字段所有的特性
                        {
                            var displayName = prop.GetCustomAttributes(typeof(DisplayAttribute), true).Length > 0 ? (prop.GetCustomAttributes(typeof(DisplayAttribute), true)[0] as DisplayAttribute).Name : null;
                            var validResult = item.Validate(oValue, prop.Name, displayName);
                            if (!validResult.IsValid) listErrorProp.Add(validResult);
                        }
                        if (listErrorProp.Count > 0) listError.Add(listErrorProp);
                    }
                    if (prop.PropertyType.IsClass && prop.PropertyType.IsGenericType)
                    {
                        var listValue = prop.GetValue(t, null);
                        foreach (var itemChild in listValue as IEnumerable)
                        {
                            if (itemChild != null) SetValid(itemChild, listError);
                        }
                    }
                }
            }
            return listError;
        }
        public static void SetThrow(this List<List<ValidResult>> list)
        {
            if (list == null || list.Count == 0) return;
            var listErrorMessage = new List<string>();
            #region 组合errorMessage
            foreach (var item in list)
            {
                var errorSb = new StringBuilder();
                foreach (var error in item)
                {
                    errorSb.Append(error.ErrorMessage).Append(" ");
                }
                listErrorMessage.Add(errorSb.ToString().TrimEnd());
            }
            #endregion
            BusinessException.Throw(string.Join("\r\n", listErrorMessage));
        }
    }
    public class ValidResult
    {
        /// <summary>
        /// 验证通过
        /// </summary>
        public bool IsValid { get; set; } = true;
        public string ErrorMessage { get; set; }
    }
    #endregion

    #region 必填项
    /// <summary>
    /// 必填项
    /// </summary>
    public class SetRequiredAttribute : SetValidAttribute
    {
        /// <summary>
        /// 必填项 errorMessage错误信息
        /// </summary>
        /// <param name="errorMessage"></param>
        public SetRequiredAttribute(string errorMessage = null)
        {
            _errorMessage = errorMessage;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? propertyName}是必需项" };
            if (string.IsNullOrWhiteSpace(Convert.ToString(oValue))) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 手机号
    /// <summary>
    /// 验证手机号
    /// </summary>
    public class SetMobileAttribute : SetValidAttribute
    {
        public SetMobileAttribute(string errorMessage = null)
        {
            _errorMessage = errorMessage;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? propertyName}格式错误" };
            if (!RegexPattern.IsMobile(Convert.ToString(oValue))) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 身份证
    /// <summary>
    /// 验证身份证
    /// </summary>
    public class SetIdCardAttribute : SetValidAttribute
    {
        public SetIdCardAttribute(string errorMessage = null)
        {
            _errorMessage = errorMessage;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? "身份证"}格式错误" };
            if (!RegexPattern.IsIdCard(Convert.ToString(oValue))) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 邮箱
    /// <summary>
    /// 验证邮箱
    /// </summary>
    public class SetEmailAttribute : SetValidAttribute
    {
        public SetEmailAttribute(string errorMessage = null)
        {
            _errorMessage = errorMessage;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? "邮箱"}格式错误" };
            if (!RegexPattern.IsEmail(Convert.ToString(oValue))) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 范围-字符串长度
    /// <summary>
    /// 范围-字符串长度
    /// </summary>
    public class SetStringRangeAttribute : SetValidAttribute
    {
        public int _minimum { get; set; }
        public int _maximum { get; set; }
        public SetStringRangeAttribute(int minimum, int maximum, string errorMessage = null)
        {
            _errorMessage = errorMessage;
            _minimum = minimum;
            _maximum = maximum;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            if (_errorMessage != null) _errorMessage = string.Format(_errorMessage, _minimum, _maximum);
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? propertyName}的长度范围应在{_minimum}到{_maximum}" };
            if (Convert.ToString(oValue).Length > _maximum || Convert.ToString(oValue).Length < _minimum) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 范围-数值
    /// <summary>
    /// 范围-数值
    /// </summary>
    public class SetRangeAttribute : SetValidAttribute
    {
        public object _minimum { get; set; }
        public object _maximum { get; set; }
        public SetRangeAttribute(double minimum, double maximum, string errorMessage = null)
        {
            _errorMessage = errorMessage;
        }
        public SetRangeAttribute(int minimum, int maximum, string errorMessage = null)
        {
            _errorMessage = errorMessage;
            _minimum = minimum;
            _maximum = maximum;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = string.Format(_errorMessage, _minimum, _maximum) ?? $"{displayName ?? propertyName}的范围应在{_minimum}到{_maximum}" };
            if (Convert.ToDouble(oValue) > Convert.ToDouble(_maximum) || Convert.ToDouble(oValue) < Convert.ToDouble(_minimum)) res.IsValid = false;
            return res;
        }
    }
    #endregion

    #region 最小-字符串长度/数组长度/数值大小
    /// <summary>
    /// 最小-字符串长度/数组长度/数值大小
    /// </summary>
    public class SetMinAttribute : SetValidAttribute
    {
        public int _minimum { get; set; }
        public SetMinAttribute(int minimum, string errorMessage = null)
        {
            _errorMessage = errorMessage;
            _minimum = minimum;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            if (_errorMessage != null) _errorMessage = string.Format(_errorMessage, _minimum);
            var res = new ValidResult();
            var defaultMessage = $"{displayName ?? propertyName}的最小长度为{_minimum}";
            if (oValue.GetType().IsArray)
            {
                if ((oValue as Array).Length < _minimum) res.IsValid = false;
            }
            else if (oValue.GetType() == typeof(string))
            {
                if (Convert.ToString(oValue).Length < _minimum) res.IsValid = false;
            }
            else if (oValue.GetType().IsValueType)
            {
                defaultMessage = $"{displayName ?? propertyName}的最小值为{_minimum}";
                if (Convert.ToDecimal(oValue) < _minimum) res.IsValid = false;
            }
            res.ErrorMessage = _errorMessage ?? defaultMessage;
            return res;
        }
    }
    #endregion

    #region 最大-字符串长度/数组长度/数值大小
    /// <summary>
    /// 最大-字符串长度/数组长度/数值大小
    /// </summary>
    public class SetMaxAttribute : SetValidAttribute
    {
        public int _maximum { get; set; }
        public SetMaxAttribute(int maximum, string errorMessage = null)
        {
            _errorMessage = errorMessage;
            _maximum = maximum;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            if (_errorMessage != null) _errorMessage = string.Format(_errorMessage, _maximum);
            var res = new ValidResult();
            var defaultMessage = $"{displayName ?? propertyName}的最大长度为{_maximum}";
            if (oValue.GetType().IsArray)
            {
                if ((oValue as Array).Length > _maximum) res.IsValid = false;
            }
            else if (oValue.GetType() == typeof(string))
            {
                if (Convert.ToString(oValue).Length > _maximum) res.IsValid = false;
            }
            else if (oValue.GetType().IsValueType)
            {
                defaultMessage = $"{displayName ?? propertyName}的最大值为{_maximum}";
                if (Convert.ToDecimal(oValue) > _maximum) res.IsValid = false;
            }
            res.ErrorMessage = _errorMessage ?? defaultMessage;
            return res;
        }
    }
    #endregion

    #region 正则验证
    /// <summary>
    /// 正则是否匹配
    /// </summary>
    public class SetRegexAttribute : SetValidAttribute
    {
        private string _pattern { get; set; }
        public SetRegexAttribute(string pattern, string errorMessage = null)
        {
            _pattern = pattern;
            _errorMessage = errorMessage;
        }
        public override ValidResult Validate(object oValue, string propertyName, string displayName)
        {
            var res = new ValidResult { ErrorMessage = _errorMessage ?? $"{displayName ?? propertyName}格式错误" };
            if (!RegexPattern.IsMatch(Convert.ToString(oValue), _pattern)) res.IsValid = false;
            return res;
        }
    }
    #endregion

}
